feat(privacy): fixed MeshView-specific notice, replaces configurable text model - #14
Open
dborup wants to merge 4 commits into
Open
feat(privacy): fixed MeshView-specific notice, replaces configurable text model#14dborup wants to merge 4 commits into
dborup wants to merge 4 commits into
Conversation
The section is removed outright rather than hidden behind a config flag:
there is no key that can bring it back. Gone from the rendered page are the
"Your rights" heading, the access/rectification/erasure/restriction/
portability/objection boilerplate, the "requests are assessed" wording, the
node hide-or-remove offer, the GDPR Art. 15-21 reference, the public-channel
note, "Send privacy requests to <contact>" and the whole complaint block
naming the supervisory authority and linking to it.
section() emits only an <h3> plus its body, so deleting the statement takes
the heading with it -- no empty wrapper, section or separator is left. The
page now runs "Hidden nodes" straight into "Automated decision-making".
Three config fields fed that section and nothing else, so they are removed
consistently across the stack:
rightsRequestText, supervisoryAuthorityName, supervisoryAuthorityUrl
- PrivacyConfig struct fields and their Validate() entries (config.go),
including the dedicated supervisoryAuthorityUrl scheme check
- PrivacyClientConfig DTO (types.go) and the /api/config/client publish
block (routes.go), so they no longer ship to any browser
- public/privacy.js reads
- config.example.json keys and their _comment_ documentation
- Go and Node test fixtures, required-field tables and assertions
Two helpers died with them and are removed too: safeUrl() in privacy.js and
isSafeHTTPURL() in config.go, each of which had exactly one call site in the
deleted code. Dropping isSafeHTTPURL also drops the now-unused net/url
import.
contactEmail is KEPT: it is rendered outside the section, in the page header
("Privacy contact:"), and still validated by privacyEmailRe.
A config.json written before this change still carries the three keys. The
decoder does not reject unknown fields, so such a deployment keeps working:
the keys are ignored, never validated and never published.
13 regression tests added (10 Node, 3 Go) pinning that none of the removed
headings, texts or links render, that stale config values cannot resurface
them, that no empty heading or wrapper is left behind, that the fields are
absent from the published API payload, and that the contact link and every
remaining section still render.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous commit trimmed one section out of a config-driven page. That missed the requirement: the notice is an approved document, and the page's visible content must be exactly that document -- no more, no less. The page is now a FIXED document. public/privacy.js carries the notice as a typed block/run structure (heading, paragraph, list, bold, link, hard break) and renders it through a closed set of tags. Config decides only WHETHER the page is published, never what it says: privacy.js reads cfg.enabled and nothing else, so no operator value -- current, stale or newly added -- can add, remove or reword a line. Removed from the rendered page (static boilerplate that was never in the approved text): the "Privacy Notice" title, effective date, data-controller and privacy-contact header, the CoreScope intro paragraph, "What data this site processes", the legal-basis label and its "stated by the operator" note, "Sources of the data", "Who can receive the data", the retention caveat, "Channel and direct messages", "Storage in your browser", "Server and proxy logs", "External services", "International transfers", "Hidden nodes", "Automated decision-making", "Changes to this notice" and the DPO block. Config fields removed, because the page no longer reads any of them and a required field that cannot affect the page is a trap -- a blank one would have withheld the notice entirely: PrivacyConfig -> Enabled only. Gone: controllerName, contactEmail, effectiveDate, purposesText, legalBasisType, legalBasisText, legitimateInterestsText, retentionText, recipientsText, dataSourcesText, thirdPartyServicesText, internationalTransfersText, browserStorageText, serverLogsText, automatedDecisionMakingText, dpoName, dpoContact. PrivacyClientConfig -> Enabled only; hiddenNamePrefixes no longer rides along in the privacy block. With no fields left to check, Validate(), logPrivacyConfigErrors(), privacyEmailRe, privacyLegalBasisTypes and PrivacyLegalBasisTypes() are gone too, and with them the regexp/sort/strconv imports. The publish gate is now just privacy.enabled. Config.ActiveHiddenNamePrefixes() is KEPT: the privacy page no longer consumes it, but its test pins an IsNameHidden invariant that belongs to node hiding. Safety: the notice is code, not config. Every text run goes through escapeHtml; the single href is a compile-time constant re-checked against an absolute-http(s) pattern at render time, and an unsafe URL degrades to plain text instead of becoming a link. Nothing from window.MC_PRIVACY reaches the DOM. A pre-removal config.json still parses and is still accepted -- its values are simply ignored and never published. Tests: a golden test normalises the rendered markup back to visible text and compares the whole result against the authoritative Markdown, held verbatim in the test (String.raw, so JS cannot eat the \. \@ escapes or the hard-break backslash before the comparison sees them). Mutation-checked: it fails on added text, removed text and a single reworded word. Alongside it: exactly 7 headings in order, exactly 4 data points with their bold lead-ins, the MeshCore URL, meshview.dk and kontakt@meshview.dk rendering without backslashes, both square-bracket passages intact, and no extra section. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…mment The comment still described the field as "operator-configured privacy-notice content" published only once the block passes PrivacyConfig.Validate(). Neither is true any more: the notice is a fixed document in public/privacy.js, Validate() no longer exists, and the block is published on privacy.enabled alone. Comment only — no code, no behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Independent review compared the rendered #/privacy notice word-for-word against the user's authoritative text (supplied directly, not sourced from this repo). Every heading, paragraph, list item, bold emphasis, line break and bracketed passage matched exactly except one: the MeshCore link pointed at https://meshcore.co.uk/, where the approved text specifies https://meshcore.io. Three call sites carried the old URL and are now aligned: - public/privacy.js: the DOC link itself (the rendered href) - test-privacy-page.js: the AUTHORITATIVE golden fixture - test-privacy-page.js: the link-safety assertion and the "notice text lives in code" static-source check No other content changed. Structure (7 headings, 4 list items, 1 link), bold segments, the controller/contact line break, and both bracketed passages were independently re-verified unchanged and byte-identical to the approved text after this fix. test-privacy-page.js: 34/34 passing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
The
#/privacypage's notice text is now the operator's (meshview.dk's) fixed, hardcoded content, not an operator-configurable template:public/privacy.jscarries the approved notice verbatim, as a typed run structure, rendered through a closed set of tags. It is MeshView-specific content, not a general-purpose privacy-policy generator.Validate()-gated text model shipped in feat(privacy): opt-in config-driven GDPR privacy-notice page (#/privacy) #12. That model is gone:PrivacyConfigandPrivacyClientConfignow carry exactly one field.config.json'sprivacyblock controls onlyprivacy.enabled— nothing else. No config value can add, remove, or reword a line of the notice.https://meshcore.io.Independent review
This branch went through an independent, read-only review by a separate agent session (no shared authorship with the implementation), covering the full commit series against baseline
651be3e0:{"enabled":true}when on, field omitted entirely when off/unconfigured), legacy config files with the old fields still load safely (values ignored, never published), no dangling references to the removed config model anywhere in the codebase.#/privacyaccess while disabled shows a neutral "not published" state; nav injection (drawer/More-sheet/desktop) has no duplicates and reconciles correctly regardless of config-arrival timing.meshcore.co.ukdomain) was corrected in this branch's final commit.This is a technical/structural/security verification, not a legal GDPR compliance approval. It confirms the code does what it claims to do and matches the text the operator approved; it does not assess the legal adequacy of that text.
Known gap
Staging verification of this exact HEAD is still pending — the independent review ran the full test suite and a local (non-network) render harness, but has not yet been verified against a live staging deployment.
Test results
test-privacy-page.js: 34/34 passingcmd/serverpackage: full suite passing (go build,go vet,go test ./...all clean)node --check,git diff --check: clean🤖 Generated with Claude Code